package  
{
	import flash.display.BitmapData;
	import flash.geom.Matrix;
	import flash.geom.ColorTransform;
	import flash.filters.BitmapFilterQuality;
	import flash.display.BitmapDataChannel;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.filters.BlurFilter;
	import org.flixel.*;
	/**
	 * ...
	 * @author morgan
	 */
	public class HazyGroup extends FlxGroup
	{
		[Embed (source = "../data/overlay.png")] private var img_overlay:Class;
		[Embed (source = "../data/mask.png")] private var img_mask:Class
		[Embed (source = "../data/inversemask.png")] private var img_inversemask:Class
		
		[Embed (source = "../data/brushLoop.mp3")] private var snd_brush:Class;
		
		// The unblur mask is a grayscale image. Black pixels are fully blurry, white pixels are fully sharp.
		public var unblurMask:BitmapData;
		// This paints in lighten mode to add white material to the unblur mask
		public var unblurBrush:BitmapData;
		// This paints in darken mode to add darkness back into the mask
		public var blurBrush:BitmapData;
		
		// Configure these per level
		public var overlayImage:BitmapData; // Overlayed only to the haze
		public var brushWeight:Number = 5.0; // How much pressure the unblur brush has
		public var blurriness:Number = 15; // How blurry the haze is (pixels)
		public var waveyness:FlxPoint = new FlxPoint(5, 3); // How wavey in both dimensions the haze is
		public var colorBase:uint = 0xff777777; // The base color of the haze
		public var colorMadness:Number = 0.2; // The intensity of the color cycling for the haze
		public var splotchInterval:Number = 0.1;
		
		private var time:Number = 0;
		private var lastPos:FlxPoint = new FlxPoint(0, 0);
		private var splotchTimer:Number = 0;
		
		// Continuous loop plays and is modulated for brushing audio
		private var brushSound:FlxSound;
		private var lastBrushVolume:Number = 0;
		
		private var haze:BitmapData;
		private var hazeTimer:Number = 0;
		
		public function HazyGroup() 
		{
			unblurBrush = FlxG.addBitmap(img_mask);
			blurBrush = FlxG.addBitmap(img_inversemask);
			unblurMask = new BitmapData(FlxG.width, FlxG.height, true, 0xff000000);
			overlayImage = FlxG.addBitmap(img_overlay);
			haze = new BitmapData(FlxG.width, FlxG.height, true);
			brushSound = FlxG.play(snd_brush, 0, true, false);
			super();
		}
		
		override public function update():void 
		{
			super.update();
			time += FlxG.elapsed;
			
			var mx:int = FlxG.mouse.x - unblurBrush.width / 2;
			var my:int = FlxG.mouse.y - unblurBrush.height / 2;
			
			var vx:Number = mx - lastPos.x;
			var vy:Number = my - lastPos.y;
			var speed:Number = Math.sqrt(vx * vx + vy * vy);
			
			var bv:Number = 0;
			
			// Only paint if the mouse has moved, so we don't get bad-looking splotches if you leave the mouse in one place.
			if (lastPos.x != mx || lastPos.y != my)
			{
				
				// Paint the brush in lighten mode.
				unblurMask.draw(unblurBrush, new Matrix(1, 0, 0, 1, mx, my), new ColorTransform(1, 1, 1, FlxG.elapsed * brushWeight, 0, 0, 0, 0), "lighten");

				var brightness:Number = FlxU.getRGBA(unblurMask.getPixel32(FlxG.mouse.x, FlxG.mouse.y))[0];
				bv = 1 - (Math.abs(80 - brightness) / 80);
				
				// This will paint splotches back onto the image so that it's always getting progressively blurrier. 
				// This way the player has to fight the system to keep things cleared.
				splotchTimer -= FlxG.elapsed;
				if (splotchTimer < 0)
				{
					splotchTimer = splotchInterval;
					var scl:Number = Math.random() + 0.5;
					var rot:Number = Math.random() * 6.2818;
					var cs:Number = Math.cos(rot);
					var sn:Number = Math.sin(rot);
					// The scale, translation, and rotation are randomized to make the system look less uniform.
					var mat:Matrix = new Matrix(scl * cs, scl * sn, scl * -sn, scl * cs, Math.random() * FlxG.width, Math.random() * FlxG.height);
					unblurMask.draw(blurBrush, mat, new ColorTransform(1, 1, 1, Math.random() / 2, 0, 0, 0, 0), "darken");
				}
			}
			bv *= 2;
			lastPos = new FlxPoint(mx, my);
			lastBrushVolume = bv * 0.1 + lastBrushVolume * 0.9;
			brushSound.volume = 0;//lastBrushVolume * 2;
		}
		
		public function calcHaze():void
		{
			haze = FlxG.camera.buffer.clone();

			// Apply a blur to the whole thing
			haze.applyFilter(haze, new Rectangle(0, 0, FlxG.width, FlxG.height), new Point(0, 0), new BlurFilter(blurriness, blurriness, BitmapFilterQuality.HIGH));
			
			// Slap the overlay on top
			haze.draw(overlayImage);
		}
		
		override public function draw():void 
		{
			super.draw();
			
			// Prepare two images, the sharp and the hazy.
			var sharp:BitmapData = FlxG.camera.buffer.clone();
			
			hazeTimer -= FlxG.elapsed;
			if (hazeTimer <= 0)
			{
				calcHaze();
				hazeTimer = 0.5;
			}
			
			var wavey:BitmapData = haze.clone()
			for (var i:int = 0; i < FlxG.height; i += 8)
			{
				wavey.copyPixels(haze, new Rectangle(0, i, FlxG.width, 8), new Point(Math.sin(time * 3 + i / 15) * waveyness.x, i));
			}			
			
			// Some color madness to evoke dreaminess
			var colorArray:Array = FlxU.getRGBA(colorBase);
			var r:Number = Math.sin(time*0.7) * colorMadness + colorArray[0]/255;
			var g:Number = Math.sin(time*0.8+2) * colorMadness + colorArray[1]/255;
			var b:Number = Math.sin(time*0.6+4) * colorMadness + colorArray[2]/255;
			wavey.colorTransform(new Rectangle(0, 0, FlxG.width, FlxG.height), new ColorTransform(0 + r, 0 + g, 0 + b, 1.0, 40, 40, 40, 0));			
			
			// Kk now draw the haze.
			FlxG.camera.buffer.draw(wavey, null, new ColorTransform(1, 1, 1, Math.min(time / 3 + 0.5, 0.9)));
			
			// Make a clone of the sharp layer which snags the unblur mask's red layer (it could be r, g, or b, it doesn't matter) as alpha.
			var ub:BitmapData = sharp.clone();
			ub.copyChannel(unblurMask, new Rectangle(0, 0, FlxG.width, FlxG.height), new Point(0, 0), BitmapDataChannel.RED, BitmapDataChannel.ALPHA);
			FlxG.camera.buffer.draw(ub);
			//FlxG.camera.buffer.draw(unblurMask);
		}		
		
	}

}